/**
 * main.c: Kernel main (entry) function
 *
 * Author: 	Nora Tarano <ntarano@andrew.cmu.edu>
 *          Yuan Meng <yuanm@andrew.cmu.edu>
 *          Yipeng Yun <yipengy@andrew.cmu.edu>
 * Date: 	Dec 11, 2011
 */
 
#include <kernel.h>
#include <task.h>
#include <sched.h>
#include <device.h>
#include <assert.h>

#include <arm/interrupt.h>
#include <arm/timer.h>
#include <arm/swi.h>

uint32_t global_data;

void * init_usr_stack(int argc, char** argv);

int kmain(int argc, char** argv, uint32_t table)
{
	task_t user_task;
	uint32_t* user_stack;

	app_startup();
	global_data = table;

	// initialize handlers
	init_interrupt();
	init_timer();
	init_swi();

	user_stack = init_usr_stack(argc, argv);
	
	// set up user tasks
	user_task.lambda = (task_fun_t) LOAD_ADDR;
	user_task.data = 0;
	user_task.stack_pos = user_stack;
	user_task.C = 0;
	user_task.T = 0;

	dev_init();

	sched_init(&user_task);
	dispatch_nosave();

	assert(0);	// control should never reach this point
}

void * init_usr_stack(int argc, char** argv) 
{
	uint32_t *user_stack = (uint32_t *) USR_STACK;
	user_stack--;

	// set terminating arg to NULL
	*user_stack = 0;
	
	// copy argvs onto user stack
	int i;
	for(i = 0; i < argc; i++)
	{
		user_stack--;
		*user_stack = (uint32_t) argv[i];
	}
	
	// copy argc onto user stack
	user_stack--;
	*user_stack = argc;
	
	return (void *)user_stack;
}
